package cn.elead.chaos.framework.util;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
import java.util.function.Consumer;

import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import cn.elead.chaos.core.exception.ApplicationException;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

/**
 * Jackson 工具类
 *
 * @author luopeng
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public abstract class JacksonUtils {

	private final static ObjectMapper objectMapper;

	static {
		objectMapper = initObjectMapper(new ObjectMapper());
	}

	/**
	 * 转换Json
	 *
	 * @param object
	 * @return
	 */
	public static String toJson(Object object) {
		if (isCharSequence(object)) {
			return (String) object;
		}
		try {
			return getObjectMapper().writeValueAsString(object);
		} catch (JsonProcessingException e) {
			throw new ApplicationException(e);
		}
	}

	/**
	 * 获取ObjectMapper
	 *
	 * @return
	 */
	public static ObjectMapper getObjectMapper() {
		return objectMapper;
	}

	/**
	 * 初始化 ObjectMapper
	 *
	 * @param objectMapper
	 * @return
	 */
	public static ObjectMapper initObjectMapper(ObjectMapper objectMapper) {
		if (Objects.isNull(objectMapper)) {
			objectMapper = new ObjectMapper();
		}
		return doInitObjectMapper(objectMapper);
	}

	/**
	 * 初始化 ObjectMapper 时间方法
	 *
	 * @param objectMapper
	 * @return
	 */
	private static ObjectMapper doInitObjectMapper(ObjectMapper objectMapper) {
		objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
		// 不显示为null的字段
		objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
		objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
		// 忽略不能转移的字符
		// objectMapper.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER,
		// true);
		objectMapper.configure(JsonReadFeature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER.mappedFeature(), true);
		// 过滤对象的null属性.
		objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
		// 忽略transient
		objectMapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);
		return registerModule(objectMapper);
	}

	/**
	 * 注册模块
	 *
	 * @param objectMapper
	 * @return
	 */
	private static ObjectMapper registerModule(ObjectMapper objectMapper) {
		SimpleModule simpleModule = new SimpleModule();
		simpleModule.addSerializer(LocalDateTime.class,
				new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
		simpleModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
		simpleModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
		simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
		objectMapper.registerModule(new JavaTimeModule());
		objectMapper.registerModule(simpleModule);
		return objectMapper;
	}

	/**
	 * 包装 MappingJackson2HttpMessageConverter
	 *
	 * @return
	 */
	public static Consumer<HttpMessageConverter<?>> wrapperObjectMapper() {
		return converter -> {
			if (converter instanceof MappingJackson2HttpMessageConverter) {
				MappingJackson2HttpMessageConverter httpMessageConverter = (MappingJackson2HttpMessageConverter) converter;
				registerModule(httpMessageConverter.getObjectMapper());
			}
		};
	}

	/**
	 * <p>
	 * 是否为CharSequence类型
	 * </p>
	 *
	 * @param object
	 * @return
	 */
	public static Boolean isCharSequence(Object object) {
		return !Objects.isNull(object)  && CharSequence.class.isAssignableFrom(object.getClass());
	}

	/**
	 * Json转换为对象 转换失败返回null
	 *
	 * @param json
	 * @return
	 */
	public static Object parse(String json) {
		Object object = null;
		try {
			object = getObjectMapper().readValue(json, Object.class);
		} catch (Exception ignored) {
		}
		return object;
	}

	/**
	 * Json转换为对象 转换失败返回null
	 *
	 * @param json
	 * @param clazz
	 * @param <T>
	 * @return
	 */
	public static <T> T readValue(String json, Class<T> clazz) {
		T t = null;
		try {
			t = getObjectMapper().readValue(json, clazz);
		} catch (Exception ignored) {
		}
		return t;
	}

	/**
	 * Json转换为对象 转换失败返回null
	 *
	 * @param json
	 * @param valueTypeRef
	 * @param <T>
	 * @return
	 */
	public static <T> T readValue(String json, TypeReference<T> valueTypeRef) {
		T t = null;
		try {
			t = getObjectMapper().readValue(json, valueTypeRef);
		} catch (Exception ignored) {
		}
		return t;
	}

}
